// Field repair by [STELS]Zealot
// Just add 
// [] execVM "zlt_fieldrepair.sqf";
// http://forums.bistudio.com/showthread.php?168714-Realistic-repair-script
// k1修改 2022.1.20 修正某些载具维修完好后炮塔无法转动bug


//uiSleep 20; //

#define DEFAULT_FIELDREPAIR_EACH_PART_TIME 10
#define DEFAULT_FIELDREPAIR_EACH_HARDPART_TIME 20
#define DEFAULT_FULLREPAIR_LENGTH 120
#define DEFAULT_REPAIR_TRUCK_USES 20
#define DEFAULT_FREE_REPAIRS 30

#define STR_FIELD_REPAIR "车辆维修"
#define STR_CANCEL_ACTION "取消动作"
#define STR_SERIOUS_REPAIR "完全修复"
#define STR_REPAIR_CONDITIONS "维修条件很不好"
#define STR_ANOTHER_ACTION "另一个动作正在进行中"
#define STR_NEED_TOOLKIT "需要你车辆里或者身上有工具包."
#define STR_REPAIR_INTERRUPTED "修复中断"
#define STR_REPAIR_FINISHED "修复完成"
#define STR_REPAIR_MSG_STRING "%2 将修复 %1 秒"
#define STR_REPAIR_TRUCK_DEPLETED "修理车里的备用零件"
#define STR_HELP "Realistic field repair (Author: Zealot) <br/>脚本为每个玩家提供修理车辆的能力.<br/><br/>修复时间40-400秒(对于重型车辆来说更久)，它可以被打断，还可以继续未完成的修炼.<br/><br/>每辆车本身存放的零部件都可以修理一段时间。下次维修时可能需要你背包或车里有工具包才行.<br/><br/>现场维修只能修复部分车辆.<br/><br/>卡车修理时间为3分钟，但能完全修复车辆。修理车可以用5次，然后备用零件就会耗尽.<br/><br/>要使用维修车，你应该坐在维修车的驾驶位上，然后查看损坏的车辆，并在菜单中选择“完全修复”.<br/><br/>翻车和船搁浅时你可以在站立姿势调出选项推动载具<br/>"
#define STR_SCRIPTS_NAME "维修手册"
#define STR_SCRIPT_NAME "车辆维修"
#define STR_PUSH_APC "推动载具"

if (!isNil "zlt_fnc_hastk") exitWith {};

zlt_repair_loop = [_this, 0, false] call BIS_fnc_param;

if (isServer) then {
	[] spawn {
		_first = true;
		while {_first || {zlt_repair_loop}} do {
			{ 
				if (getRepairCargo _x > 0) then {
					_x setRepairCargo 0;
					_x setVariable ["zlt_repair_cargo", 1, true]; 
				};
			} forEach vehicles;
			_first = false;
			sleep 26;
		};
	};
};

zlt_fnc_partrepair = {
	_veh = _this;
	if (isNull _veh) exitWith {};
	{
		_dmg = (_veh getHitPointDamage _x);
		if (!isNil "_dmg" && {_dmg > .64}) then {
			if (_x in zlt_hardRepairParts) then {
				_veh setHitPointDamage [_x,.64];
			} else {
				_veh setHitPointDamage [_x,0];
			};
		};
	} forEach zlt_repair_hps; 
	
	if (({(_veh getHitPointDamage _x) > 0} count zlt_repair_hps) == 0) then {_veh setDamage 0};//
};

/*Push_fn_k1 = {
	params ["_veh", "_dir", "_spd"];
	_veh setVelocity [(sin _dir)*_spd, (cos _dir)*_spd, 0]; 
};*/
	Push_fn_k1 = {
		params ["_veh", "_dir", "_spd"];
		_vel = velocity _veh;
		_veh setVelocity [(_vel select 0)+(sin _dir*_spd),(_vel select 1)+(cos _dir*_spd),(_vel select 2)];
		Push_k1_t = time + 3;
		if (isNil "Push_k1_debug") then {
			Push_k1_debug = 1;
			waitUntil {time > Push_k1_t};
			_veh setVelocity [0,0,0];
			Push_k1_debug = nil;
		};
	};

zlt_repair_hps = ["HitLFWheel","HitLBWheel","HitLMWheel","HitLF2Wheel","HitRFWheel","HitRBWheel","HitRMWheel","HitRF2Wheel" ,"HitEngine", "HitLTrack","HitRTrack"] + ["HitFuel","HitAvionics","HitVRotor","HitHRotor"];
zlt_hardRepairParts = ["HitEngine", "HitLTrack","HitRTrack"] + ["HitFuel","HitAvionics","HitHRotor"];

if (isDedicated) exitWith {};


zlt_mutexAction = false;

zlt_fnc_vehicledamaged = {
	private ["_veh","_vehtype","_flag"];
	_veh =  [_this, 0] call BIS_fnc_param;
	if (isNil {_veh}) exitWith {false};
	_vehtype = typeOf _veh;
	_flag = false;
	if (true) then {
		{
			_cdmg = _veh getHitPointDamage (_x);
			if (!isNil {_cdmg} ) then {
				if (_cdmg > 0.64) exitWith {_flag = true};
			};
		}  forEach zlt_repair_hps;
	};
	_flag;
};

zlt_frpr_getPartsRepairTime = {
	private ["_veh","_vehtype","_flag"];
	_veh =  [_this, 0] call BIS_fnc_param;
	if (isNil {_veh}) exitWith {1};
	_rprTime = 0;
	{
		_cdmg = _veh getHitPointDamage (_x);
		if (!isNil {_cdmg} ) then {
			diag_log str ["REPAIR ", _x, _cdmg];
			if (_cdmg > 0.64) exitWith {_rprTime = _rprTime + ( if (_x in zlt_hardRepairParts) then {DEFAULT_FIELDREPAIR_EACH_HARDPART_TIME} else {DEFAULT_FIELDREPAIR_EACH_PART_TIME}); };
		};
	}  forEach zlt_repair_hps;
	_rprTime;
};

zlt_fnc_notify = {
	[ format["<t size='0.75' color='#ffff00'>%1</t>",_this], 0,1,5,0,0,301] spawn bis_fnc_dynamicText;
};

zlt_fnc_hastk = {
	private ["_ret"];
	_ret = 0;
	if ("ToolKit" in (items player)) then {_ret = 1;};
	if ("ToolKit" in (itemCargo _veh)) then {_ret = 2;};
	if ( (_veh getVariable ["zlt_longrepair_times",0] ) < DEFAULT_FREE_REPAIRS) then {_ret = 3;};
	_ret;
};

zlt_fnc_removeitemfromcargo = {
	private ["_veh"];
	_item = [_this,0,""] call BIS_fnc_param;
	_veh = [_this,1] call BIS_fnc_param;
	_allitems = itemcargo _veh;
	clearItemCargoGlobal _veh;
	_allitems = _allitems call BIS_fnc_consolidateArray;
	_n = [_allitems, _item] call BIS_fnc_findInPairs;
	_allitems set [_n, [(_allitems select _n) select 0, ((_allitems select _n) select 1) - 1]];
    { _veh addItemCargoGlobal [_x select 0, _x select 1 ];} forEach _allitems;
};

zlt_prc_repairvehicle = {
	private ["_veh"];
	_veh = (nearestObjects [player,["LandVehicle","Air","Ship"], 7]) select 0;
	if (isNil {_veh}) exitWith {};
	if (zlt_mutexAction) exitWith {
		STR_ANOTHER_ACTION call zlt_fnc_notify;
	};
	if (!alive player || {(player distance _veh) > 7} || {vehicle player != player} || {speed _veh > 3}) exitWith {STR_REPAIR_CONDITIONS call zlt_fnc_notify;};
	_hastk = call zlt_fnc_hastk;
	if ( _hastk == 0 ) exitWith {STR_NEED_TOOLKIT call zlt_fnc_notify;};
	_repairFinished = false;
	zlt_mutexAction = true;  
	_lastPlayerState = animationState player;
	player playActionNow "medicStartRightSide";
	sleep 0.5;
	_maxlength = _veh getVariable["zlt_longrepair",[_veh] call zlt_frpr_getPartsRepairTime];
	_vehname = getText ( configFile >> "CfgVehicles" >> typeOf(_veh) >> "displayName");
	_length = _maxlength;
	_cycle = 0;
	while {alive player && {(player distance _veh) < 7} && {vehicle player == player} && {speed _veh < 3} && {!_repairFinished} && {zlt_mutexAction} && {_cycle < 3 || {["medic",animationState player] call BIS_fnc_inString}}} do {	
	//	diag_log ("ANIM STATE = "+str(animationState player));	
		(format[STR_REPAIR_MSG_STRING, _length, _vehname] ) call zlt_fnc_notify;
		if (_length <= 0) then {_repairFinished = true;};
		_length = _length - 1;
		sleep 1;
		_hastk = call zlt_fnc_hastk;
		if (_hastk <= 0) exitWith {STR_NEED_TOOLKIT call zlt_fnc_notify; sleep 1.;};	
		_cycle = _cycle + 1;
	};
	if (_repairFinished) then {
		_hastk = call zlt_fnc_hastk;
		if (_hastk == 0) exitWith {STR_NEED_TOOLKIT call zlt_fnc_notify; sleep 1.;};	
		STR_REPAIR_FINISHED call zlt_fnc_notify;
		//[_veh,"zlt_fnc_partrepair", _veh] call bis_fnc_MP;
		_veh remoteExec ["zlt_fnc_partrepair", _veh];//
		if (_hastk == 1) then {player removeItem "ToolKit";};
		if (_hastk == 2) then { ["ToolKit",_veh] call zlt_fnc_removeitemfromcargo;};
		_veh setVariable["zlt_longrepair",nil, true];
		_veh setVariable["zlt_longrepair_times", (_veh getVariable ["zlt_longrepair_times",0]) + 1 , true ];
	} else {
		STR_REPAIR_INTERRUPTED call zlt_fnc_notify;
		_veh setVariable["zlt_longrepair",_length, true];
	};
	zlt_mutexAction = false;  
	player playActionNow "medicstop";
};

zlt_fnc_repair_cond = {
	private ["_veh","_ret"];
	_ret = false;
	_veh = (nearestObjects [player,["LandVehicle","Air","Ship"], 7]) select 0;
	if (isNil {_veh}) exitWith {_ret};
	_dmged = _veh call zlt_fnc_vehicledamaged;
	_ret = (alive player && {player distance _veh <= 7} && {vehicle player == player} && {speed _veh < 3} && {!zlt_mutexAction} && {_dmged} && {alive _veh});
	_ret;
};

zlt_fnc_heavyRepair = {
	_caller = player;
	_truck = vehicle _caller;
	_veh = cursorTarget;
	if (isNil "_veh" || {isNull _truck} || {isNull _veh}) exitWith {false};
	
	if (zlt_mutexAction) exitWith {
		STR_ANOTHER_ACTION call zlt_fnc_notify;
	};
	if (_truck getVariable ["zlt_repair_cargo", 0] <= 0) then {
		STR_REPAIR_TRUCK_DEPLETED call zlt_fnc_notify;
	};
	
	if (!alive player || {vehicle player == player} || {speed _veh > 3} || {(_veh distance _truck) > 15} ) exitWith {STR_REPAIR_CONDITIONS call zlt_fnc_notify;};
	
	_repairFinished = false;
	zlt_mutexAction = true;	
	_maxlength = _veh getVariable["zlt_longrepairTruck",DEFAULT_FULLREPAIR_LENGTH];
	_vehname = getText (configFile >> "CfgVehicles" >> typeOf _veh >> "displayName");
	_length = _maxlength;
	while { alive player && { alive _truck} && {alive _veh} && {vehicle _caller != _caller} && {speed _veh <= 3} && {!_repairFinished} && {zlt_mutexAction} && {_veh distance _truck <= 15} } do {			
		(format[STR_REPAIR_MSG_STRING, _length, _vehname] ) call zlt_fnc_notify;
		if (_length <= 0) then {_repairFinished = true;};
		_length = _length - 1;
		sleep 1;
	};
	
	if (_repairFinished) then {
		STR_REPAIR_FINISHED call zlt_fnc_notify;
		//[_veh,"zlt_fnc_fullrepair", _veh] call bis_fnc_MP;
		_veh setDamage 0;//
		_truck setVariable ["zlt_repair_cargo", ( (_truck getVariable ["zlt_repair_cargo", 0] )- (1 / DEFAULT_REPAIR_TRUCK_USES) ), true] ;
		
		_veh setVariable["zlt_longrepairTruck", nil, true];
		_veh setVariable["zlt_fullrepair_times", (_veh getVariable ["zlt_fullrepair_times",0]) + 1 , true ];
	} else {
		STR_REPAIR_INTERRUPTED call zlt_fnc_notify;
		_veh setVariable["zlt_longrepairTruck",_length, true];
	};
	zlt_mutexAction = false;  	
};

zlt_fnc_heavyRepairCOnd = {
	_truck = vehicle player;
	_veh = cursorTarget;
	if (isNull _truck || {isNull _veh}) exitWith {false};
	_isRepair = _truck getVariable ["zlt_repair_cargo", -1];
	if (_isRepair == -1) exitWith {false};
	
	_res = (_veh distance _truck <= 15 && {player == driver _truck} && {_veh isKindOf "LandVehicle" || {_veh isKindOf "Ship"} || {_veh isKindOf "Air"}} && {alive _truck} && {alive player} && {alive _veh} && {!zlt_mutexAction} && {speed _veh <= 3} && {damage _veh != 0});
	_res;
};// obsolete


zlt_pushapc = {
	if (isNil "Push_speed_k1") then {Push_speed_k1 = 5};
	_veh = cursorTarget;
	if (local _veh) then [{
		[_veh, direction player, Push_speed_k1] call Push_fn_k1;
	},{
		[_veh, direction player, Push_speed_k1] remoteExec ["Push_fn_k1", 0];
	}];
};//

Push_k1_Check2 = {
	_return = false;
	private _target = cursorTarget;
	if (!isNull _target && {_target isKindOf "LandVehicle" || {_target isKindOf "Ship"} || {_target isKindOf "StaticWeapon"} || {_target isKindOf "air"}} && {(_target distance player) < 8} && {stance player == "STAND"} && {vehicle player == player}) then { _return = true };
	_return
};//


waitUntil {!isNull player};
if (isNil "zlt_cancelActionId") then {
	player createDiarySubject [STR_SCRIPTS_NAME,STR_SCRIPTS_NAME];
	player createDiaryRecord [STR_SCRIPTS_NAME,[STR_SCRIPT_NAME, STR_HELP]];
	0 spawn {
		private ["_play", "_idx1", "_idx2", "_idx3"];
		_idx1 = -1;
		while {true} do {
			if (_idx1 == -1) then {
				zlt_cancelActionId = player addAction ["<t color='#0000ff'>"+STR_CANCEL_ACTION+"</t>", {zlt_mutexAction = false}, [], 10, false, true, '','zlt_mutexAction'];
				_idx1 = player addAction ["<t color='#ff0000'>"+STR_FIELD_REPAIR+"</t>", zlt_prc_repairvehicle, [], -1, false, true, '','[] call zlt_fnc_repair_cond'];
				_idx2 = player addAction ["<t color='#ff0000'>"+STR_SERIOUS_REPAIR+ "</t>", zlt_fnc_heavyRepair, [], -1, false, true, '','_truck=(vehicle player);_truck getVariable ["zlt_repair_cargo", -1] != -1 && {alive cursorTarget} && {(_truck distance cursorTarget) <= 15} && {cursorTarget isKindOf "LandVehicle" || {cursorTarget isKindOf "Ship"} || {cursorTarget isKindOf "Air"}} && {!zlt_mutexAction} && {speed cursorTarget <= 3} && {damage cursorTarget != 0}'];
				//_idx1 = player addAction ["<t color='#FF9900'>"+STR_PUSH_APC+"</t>",zlt_pushapc,[],5,false,true,"","canMove (vehicle player) && {(vehicle player) isKindOf 'Wheeled_APC_F'} && {player == driver (vehicle player)} && {surfaceIsWater getPosASL (vehicle player)} && {abs(speed (vehicle player)) < 3} && {!zlt_mutexAction}"];
				_idx3 = player addAction ["<t color='#FF9900'>"+STR_PUSH_APC+"</t>",zlt_pushapc,[],-55,false,false,"","call Push_k1_Check2"];//
				
				_play = player;
			};
			if (_play != player) then {
				{_play removeAction _x} forEach [zlt_cancelActionId, _idx1, _idx2, _idx3];
		    	_idx1 = -1;
			};
			sleep 5;
		};
	};
};







